package com.lin.config;

import com.lin.filter.JWTFilter;
import com.lin.realm.AdminRealm;
import com.lin.realm.UserRealm;
import com.lin.shiro.MyModularRealmAuthenticator;
import net.sf.ehcache.CacheManager;
import org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy;
import org.apache.shiro.authc.pam.ModularRealmAuthenticator;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.io.ResourceUtils;
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.spring.web.config.DefaultShiroFilterChainDefinition;
import org.apache.shiro.spring.web.config.ShiroFilterChainDefinition;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.Filter;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;

/**
 * @author 霖霖
 * @version 1.0
 * @date 2023/3/29 9:08
 * @Description 配置管理方式
 */
@Configuration
public class ShiroConfig {

    @Autowired
    private AdminRealm adminRealm;
    @Autowired
    private UserRealm userRealm;

    @Bean("shiroFilterFactoryBean")
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();


        shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);

        shiroFilterFactoryBean.setLoginUrl("/Unauthenticated/login");

        Map<String, Filter> filterHashMap = new LinkedHashMap<>();

        filterHashMap.put("jwt",new JWTFilter());
        shiroFilterFactoryBean.setFilters(filterHashMap);

//        Map<String, String> limit = new LinkedHashMap<>(32);
//        limit.put("/preschool/course/**","anon");
//        limit.put("/banner","anon");
//        limit.put("/teacher/login","anon");
//        limit.put("/preschool/index","anon");
//        limit.put("/preschool/user/login","anon");
//        limit.put("/admin/login","anon");
//        limit.put("/course/uploadCover","anon");
//        limit.put("/video/uploadVideo","anon");
//        limit.put("/admin/subject/getSubject","anon");
////        limit.put("/course/courseInfos","anon");
//        limit.put("/preschool/send/**","anon");
//        limit.put("/preschool/teacher/**","anon");
//        // 所有请求通过我们自己的JWT Filter
//        limit.put("/**","jwt");

        DefaultShiroFilterChainDefinition defaultShiroFilterChainDefinition = new DefaultShiroFilterChainDefinition();
        defaultShiroFilterChainDefinition.addPathDefinition("/teacher/login","anon");
        defaultShiroFilterChainDefinition.addPathDefinition("/preschool/user/login","anon");
        defaultShiroFilterChainDefinition.addPathDefinition("/admin/login","anon");
        defaultShiroFilterChainDefinition.addPathDefinition("/preschool/index","anon");
        defaultShiroFilterChainDefinition.addPathDefinition("/banner","anon");
        defaultShiroFilterChainDefinition.addPathDefinition("/course/uploadCover","anon");
        defaultShiroFilterChainDefinition.addPathDefinition("/video/uploadVideo","anon");
        defaultShiroFilterChainDefinition.addPathDefinition("/admin/subject/getSubject","anon");
        defaultShiroFilterChainDefinition.addPathDefinition("/course/courseInfos","anon");
        defaultShiroFilterChainDefinition.addPathDefinition("/preschool/send/**","anon");
        defaultShiroFilterChainDefinition.addPathDefinition("/preschool/teacher/**","anon");
        defaultShiroFilterChainDefinition.addPathDefinition("/preschool/course/**","anon");

        defaultShiroFilterChainDefinition.addPathDefinition("/**","jwt");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(defaultShiroFilterChainDefinition.getFilterChainMap());
        return shiroFilterFactoryBean;
    }

//    @Bean(name = "shiroFilterFactoryBean")
    public static ShiroFilterFactoryBean factoryBean(DefaultWebSecurityManager defaultWebSecurityManager, ShiroFilterChainDefinition shiroFilterChainDefinition, FilterRegistrationBean jwtFilterRegistrationBean){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
        shiroFilterFactoryBean.setLoginUrl("/Unauthenticated/login");
        Map<String, Filter> filterMap = new LinkedHashMap<>(32);
        filterMap.put("jwt",jwtFilterRegistrationBean.getFilter());
        shiroFilterFactoryBean.setFilters(filterMap);
        shiroFilterFactoryBean.setFilterChainDefinitionMap(shiroFilterChainDefinition.getFilterChainMap());
        return shiroFilterFactoryBean;
    }
    public ShiroFilterChainDefinition shiroFilterChainDefinition(){
        DefaultShiroFilterChainDefinition defaultShiroFilterChainDefinition = new DefaultShiroFilterChainDefinition();
        defaultShiroFilterChainDefinition.addPathDefinition("/teacher/login","anon");
        defaultShiroFilterChainDefinition.addPathDefinition("/chat/tts2","anon");
        defaultShiroFilterChainDefinition.addPathDefinition("/chat/tts","anon");
        defaultShiroFilterChainDefinition.addPathDefinition("/preschool/user/login","anon");
        defaultShiroFilterChainDefinition.addPathDefinition("/admin/login","anon");
        defaultShiroFilterChainDefinition.addPathDefinition("/preschool/index","anon");
        defaultShiroFilterChainDefinition.addPathDefinition("/banner","anon");
        defaultShiroFilterChainDefinition.addPathDefinition("/course/uploadCover","anon");
        defaultShiroFilterChainDefinition.addPathDefinition("/video/uploadVideo","anon");
        defaultShiroFilterChainDefinition.addPathDefinition("/admin/subject/getSubject","anon");
        defaultShiroFilterChainDefinition.addPathDefinition("/course/courseInfos","anon");
        defaultShiroFilterChainDefinition.addPathDefinition("/preschool/send/**","anon");
        defaultShiroFilterChainDefinition.addPathDefinition("/preschool/teacher/**","anon");
        defaultShiroFilterChainDefinition.addPathDefinition("/preschool/course/**","anon");

        defaultShiroFilterChainDefinition.addPathDefinition("/**","authc");
        return defaultShiroFilterChainDefinition;
    }

    public FilterRegistrationBean<JWTFilter> jwtFilterRegistrationBean(){
        FilterRegistrationBean<JWTFilter> filterRegistrationBean = new FilterRegistrationBean<>();

        filterRegistrationBean.setFilter(new JWTFilter());
        filterRegistrationBean.setEnabled(false);
        return filterRegistrationBean;
    }
    @Bean
    public DefaultWebSecurityManager getDefaultWebSecurityManager(){

        DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();

        defaultWebSecurityManager.setAuthenticator(getModularRealmAuthenticator());
        List<Realm> realms = new ArrayList<>();
        realms.add(adminRealm);
        realms.add(userRealm);
        defaultWebSecurityManager.setRealms(realms);

        DefaultSubjectDAO defaultSubjectDAO = new DefaultSubjectDAO();

        DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();

        defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
        defaultSubjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);

        defaultWebSecurityManager.setSubjectDAO(defaultSubjectDAO);
        defaultWebSecurityManager.setCacheManager(getEhCacheManager());
        return defaultWebSecurityManager;

    }

    @Bean
    public ModularRealmAuthenticator getModularRealmAuthenticator(){
        MyModularRealmAuthenticator modularRealmAuthenticator = new MyModularRealmAuthenticator();
        modularRealmAuthenticator.setAuthenticationStrategy(new AtLeastOneSuccessfulStrategy());
        return modularRealmAuthenticator;
    }


    public EhCacheManager getEhCacheManager(){
        EhCacheManager ehCacheManager = new EhCacheManager();
        InputStream inputStream=null;
        try {
            inputStream= ResourceUtils.getInputStreamForPath("classpath:ehcache/ehcache-shiro.xml");
        }catch (IOException e){
            e.printStackTrace();
        }
        CacheManager cacheManager = new CacheManager(inputStream);
        ehCacheManager.setCacheManager(cacheManager);
        return ehCacheManager;
    }

    @Bean
    public static DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        /**
         * setUsePrefix(false)用于解决一个奇怪的bug。在引入spring aop的情况下。
         * 在@Controller注解的类的方法中加入@RequiresRole等shiro注解，会导致该方法无法映射请求，导致返回404。
         * 加入这项配置能解决这个bug
         */
        defaultAdvisorAutoProxyCreator.setUsePrefix(true);
        return defaultAdvisorAutoProxyCreator;
    }
}
